import uthread
import blue
import log
import types
import uiutil
import uiconst
import uicls
import uitest
import trinity
import sys
import traceback
from util import ResFile

class UIDeviceResource:

    def __init__(self):
        dev = trinity.GetDevice()
        dev.RegisterResource(self)



    def OnInvalidate(self, level):
        return 



    def OnCreate(self, dev):
        if (getattr(uicore, 'uilib', None) is None):
            return 
        uicore.UpdateCursor(uicore.uilib.mouseOver, 1)
        uicore.CheckHint()




class UICoreBase:
    __guid__ = 'uicls.uicore'

    def __init__(self):
        import __builtin__
        if ('uicore' in __builtin__.__dict__.keys()):
            pass
        else:
            self.newRendererEnabled = False
            self._lastCursor = None
            self._cursorSprite = None
            self._hint = None
            self._startedUp = False
            self.desktop = None
            self.dragData = None
            self.triapp = None
            self.triappargs = {'title': boot.appname,
             'left': 0,
             'top': 0,
             'colordepth': 0,
             'exclusiveInput': 0,
             'refreshrate': 0}
            __builtin__.uicore = self
        blue.pyos.exceptionHandler = self._ExceptionHandler
        log.SetUiMessageFunc(self.Message)
        self.deviceResource = UIDeviceResource()



    def StartupEve(self, layerlist):
        self.LoadSettingsEve()
        deviceSvc = sm.StartService('device')
        deviceSvc.CreateDevice()
        self.device = deviceSvc
        uicls._ExposeCoreClassesWithOutCorePostfix()
        triapp = blue.rot.GetInstance('app:/App', 'triui.App')
        self.triapp = triapp
        self.tridev = triapp.tridev
        self.uilib = triapp.uilib
        eve.triapp = triapp
        self.make = sm.StartServiceAndWaitForRunningState('make')
        self.font = sm.StartServiceAndWaitForRunningState('font')
        self.LoadLayers(layerlist)
        for serviceName in ['event',
         'registry',
         'audio',
         'ime',
         'cmd']:
            setattr(self, serviceName, sm.StartServiceAndWaitForRunningState(serviceName))

        self.loading = sm.GetService('loading')
        self.effect = uicls.UIEffects()
        uthread.new(sm.GetService('event').InitAccelerators)
        self.Message = eve.Message
        import uix
        uiutil.AskName = uix.NamePopup
        log.SetUiMessageFunc(self.Message)
        self._startedUp = True



    def Startup(self, layerlist):
        self.LoadSettings()
        deviceSvc = sm.StartServiceAndWaitForRunningState('device')
        deviceSvc.CreateDevice()
        deviceSvc.PrepareMain()
        self.device = deviceSvc
        uicls._ExposeCoreClassesWithOutCorePostfix()
        triapp = blue.rot.GetInstance('app:/App', 'triui.App')
        self.triapp = triapp
        self.tridev = triapp.tridev
        self.uilib = triapp.uilib
        self.LoadLayers(layerlist)
        for serviceName in ['event',
         'font',
         'registry',
         'loading',
         'audio',
         'ime',
         'cmd']:
            setattr(self, serviceName, sm.StartServiceAndWaitForRunningState(serviceName))

        self.effect = uicls.UIEffects()
        uthread.new(sm.GetService('event').InitAccelerators)
        self._startedUp = True



    def LoadLayers(self, layerlist):
        self.layer = uiutil.Bunch()
        self.layer.Get = self.GetLayer
        self.layerData = {}
        self.layerList = layerlist
        self.CreateDesktop()
        layerlist = (layerlist or self.GetDefaultLayers())
        for (layerName, className, subLayers,) in layerlist:
            self.desktop.AddLayer(layerName, className, subLayers)




    def DestroyDesktops(self):
        if isinstance(self.desktop, uitest.Desktop):
            self.desktop.Close()
        else:
            for each in self.desktop.children[:]:
                if hasattr(each, 'Close'):
                    each.Close()
                else:
                    self.desktop.children.remove(each)

        self.desktop = None
        if getattr(self, 'scene', None):
            self.scene.preRenderCb = None
        self.scene = None
        trinity.device.scene2 = None
        trinity.device.ui.display = 0
        self.KillOldCursor()



    def CreateDesktop(self):
        if self.newRendererEnabled:
            scene = trinity.Tr2Sprite2dScene()
            view = trinity.TriView()
            view.SetLookAtPosition((0, 0, 1000), (0, 0, 0), (0, -1, 0))
            rj = sm.GetService('sceneManager').renderLoopJob
            rj.SetView(view)
            rj.Update(scene)
            rj.RenderScene(scene)
            desktop = uitest.Desktop(name='desktop', align=uiconst.RELATIVE, width=trinity.device.width, height=trinity.device.height, state=uiconst.UI_NORMAL)
            self.scene = scene
            self.desktop = desktop
            self.view = view
            desktop.UpdateAlignment()
            scene.width = trinity.device.width
            scene.height = trinity.device.height
            scene.children.append(desktop)
            curveSet = trinity.TriCurveSet()
            scene.curveSets.append(curveSet)
            desktop.curveSet = curveSet
            curveSet.Play()
            self.scene.preRenderCb = self.PreRenderTick
        else:
            (dw, dh,) = (self.uilib.desktop.width, self.uilib.desktop.height)
            desktop = uicls.LayerCore(self.uilib.desktop, pos=(0,
             0,
             dw,
             dh), name='desktop', state=uiconst.UI_NORMAL)
            self.desktop = desktop
            trinity.device.ui.display = True



    def PreRenderTick(self, *args):
        now = blue.os.GetTime()
        if (getattr(self, '_lastAlignmentUpdateTime', None) != now):
            self.desktop.UpdateAlignment()
            self._lastAlignmentUpdateTime = now
        self.desktop.UpdateCursor()



    def KillOldCursor(self):
        dev = trinity.device
        sur = dev.CreateOffscreenPlainSurface(32, 32, trinity.TRIFMT_A8R8G8B8, trinity.TRIPOOL_SCRATCH)
        sur.LoadSurfaceFromFile(ResFile('res:/uicore/cursors/cursor10.dds'))
        self.uilib.SetCursorProperties(16, 15, sur)



    def EnableNewUICoreRender(self):
        if self.newRendererEnabled:
            return 
        self.newRendererEnabled = True
        self.event.InitAccelerators()
        self.DestroyDesktops()
        uicls.Container.__bases__ = (uicls.NewContainer)
        uicls.Sprite.__bases__ = (uicls.NewSprite)
        uicls.Fill.__bases__ = (uicls.NewFill)
        uicls.LabelCore.__bases__ = (uicls.NewLabelCore)
        uicls.Frame.__bases__ = (uicls.NewFrame)
        uicls.Transform.__bases__ = (uicls.NewTransform)
        self.LoadLayers(self.layerList)



    def DisableNewUICoreRender(self):
        if not self.newRendererEnabled:
            return 
        self.newRendererEnabled = False
        self.event.InitAccelerators()
        self.DestroyDesktops()
        uicls.Container.__bases__ = (uicls.OldContainer)
        uicls.Sprite.__bases__ = (uicls.OldSprite)
        uicls.Fill.__bases__ = (uicls.OldFill)
        uicls.LabelCore.__bases__ = (uicls.OldLabelCore)
        uicls.Frame.__bases__ = (uicls.FrameCore)
        uicls.Transform.__bases__ = (uicls.OldTransform)
        self.LoadLayers(self.layerList)



    def GetDefaultLayers(self):
        layers = [('l_hint', None, None),
         ('l_menu', None, None),
         ('l_modal', None, None),
         ('l_abovemain', None, None),
         ('l_main', None, None),
         ('l_loading', None, None),
         ('l_dragging', None, None),
         ('l_tabs', None, None)]
        return layers



    def OnUilibEvent(self, item, msgID, args):
        if (msgID == uiconst.UI_MOUSEDOWN):
            if not uiutil.IsUnder(item, self.layer.menu):
                uiutil.Flush(self.layer.menu)
            self.registry.SetFocus(item)



    def CheckCursor(self):
        self.UpdateCursor(uicore.uilib.mouseOver)



    def CheckHint(self):
        self.UpdateHint(uicore.uilib.mouseOver)



    def UpdateHint(self, item, force = 0):
        if self._startedUp:
            if ((self._hint is None) or self._hint.destroyed):
                uiutil.Flush(self.layer.hint)
                self._hint = uicls.Hint(name='hint', parent=self.layer.hint, align=uiconst.RELATIVE)
            self._hint.LoadHintFromItem(item, force)



    def UpdateCursor(self, item, force = 0):
        if (uicore.desktop.state == uiconst.UI_HIDDEN):
            return 
        cursor = '00'
        ic = getattr(item, 'cursor', None)
        if ((ic is not None) and (ic >= 0)):
            cursor = str(ic)
            if (len(cursor) == 1):
                cursor = ('0' + cursor)
        elif getattr(item, 'OnChar', None):
            cursor = '07'
        else:
            hasGetMenu = getattr(item, 'GetMenu', None)
            if (getattr(item, 'OnClick', None) or getattr(item, '_OnClick', None)):
                if hasGetMenu:
                    cursor = '22'
                else:
                    cursor = '01'
            elif hasGetMenu:
                cursor = '12'
        if (force or (self._lastCursor != cursor)):
            dev = trinity.device
            sur = dev.CreateOffscreenPlainSurface(32, 32, trinity.TRIFMT_A8R8G8B8, trinity.TRIPOOL_SCRATCH)
            if prefs.GetValue('useAlphaCursor', False):
                sur.LoadSurfaceFromFile(ResFile('res:/uicore/alphacursor.dds'))
            else:
                sur.LoadSurfaceFromFile(ResFile(('res:/uicore/cursors/cursor%s.dds' % cursor)))
            self.uilib.SetCursorProperties(16, 15, sur)
            self._lastCursor = cursor



    def SaveSettings(self):
        import __builtin__
        if hasattr(__builtin__, 'settings'):
            for (sectionName, section,) in settings.iteritems():
                if isinstance(section, uiutil.SettingSection):
                    section.WriteToDisk(True)




    def LoadSettingsEve(self):
        import __builtin__
        self.SaveSettings()
        settingSections = (('public', None),
         ('user', session.userid),
         ('char', session.charid))
        __builtin__.settings = uiutil.Bunch()
        for (sectionName, identifier,) in settingSections:
            filePath = (blue.os.settingspath + ('core_%s_%s.dat' % (sectionName, (identifier or '_'))))
            section = uiutil.SettingSection(sectionName, filePath, 62)
            __builtin__.settings.Set(sectionName, section)

        settings.public.CreateGroup('generic')
        settings.public.CreateGroup('device')
        settings.public.CreateGroup('ui')
        settings.public.CreateGroup('audio')
        settings.user.CreateGroup('tabgroups')
        settings.user.CreateGroup('windows')
        settings.user.CreateGroup('suppress')
        settings.user.CreateGroup('ui')
        settings.user.CreateGroup('cmd')
        settings.user.CreateGroup('audio')
        settings.user.CreateGroup('overview')
        settings.user.CreateGroup('notifications')
        settings.char.CreateGroup('ui')
        settings.char.CreateGroup('generic')
        settings.char.CreateGroup('autorepeat')
        settings.char.CreateGroup('autoreload')
        settings.char.CreateGroup('inbox')
        settings.char.CreateGroup('notepad')
        try:
            self.FixListgroupSettings()
        except Exception:
            settings.char.ui.Set('listgroups', {})
            log.LogError('Something happened when fixing listgroups settings and they had to be deleted')



    def FixListgroupSettings(self):
        if not session.charid:
            return 
        if settings.char.ui.Get('listgroupSettingsUpdated', 0):
            return 
        for (key, value,) in settings.char.ui.Get('listgroups', {}).iteritems():
            for (key2, value2,) in value.iteritems():
                items = value2.pop('items', None)
                if (items is not None):
                    value2['groupItems'] = items


        settings.char.ui.Set('listgroupSettingsUpdated', 1)



    def LoadSettings(self):
        import __builtin__
        self.SaveSettings()
        settingSections = (('public', None),
         ('user', session.userid),
         ('char', session.charid))
        __builtin__.settings = uiutil.Bunch()
        for (sectionName, identifier,) in settingSections:
            filePath = (blue.os.settingspath + ('core_%s_%s.dat' % (sectionName, (identifier or '_'))))
            section = uiutil.SettingSection(sectionName, filePath, 62)
            __builtin__.settings.Set(sectionName, section)

        settings.public.CreateGroup('generic')
        settings.public.CreateGroup('device')
        settings.public.CreateGroup('ui')
        settings.public.CreateGroup('audio')
        settings.user.CreateGroup('tabgroups')
        settings.user.CreateGroup('windows')
        settings.user.CreateGroup('suppress')
        settings.user.CreateGroup('ui')
        settings.user.CreateGroup('cmd')
        settings.user.CreateGroup('localization')
        settings.char.CreateGroup('ui')



    def GetLayer(self, name):
        if self.desktop:
            return self.desktop.GetLayer(name)



    def Message(self, *args, **kw):
        if (args and (args[0] == 'IgnoreToTop')):
            return 
        if ((not hasattr(self, 'uilib')) or (not getattr(self.uilib, 'desktop', None))):
            return 
        import stackless
        curr = stackless.getcurrent()
        if curr.is_main:
            uthread.new(self._Message, *args, **kw).context = 'uicore.Message'
        else:
            return apply(self._Message, args, kw)



    def SimpleMessage(self, title, body, buttons = uiconst.OK):
        return self.Message('CustomQuestion', dict={'header': title,
         'question': body}, buttons=buttons)



    def _Message(self, msgkey, dict = None, buttons = None, suppress = None, prioritize = 0, ignoreNotFound = 0, default = None, modal = True):
        if (type(msgkey) not in types.StringTypes):
            raise RuntimeError('Invalid argument, msgkey must be a string', msgkey)
        try:
            msg = cfg.GetMessage(msgkey, dict, onNotFound='raise')
        except RuntimeError, what:
            if (what.args[0] == 'ErrMessageNotFound'):
                if ignoreNotFound:
                    return 
                log.LogTraceback()
                msg = cfg.GetMessage(msgkey, dict, onNotFound='return')
            else:
                raise 
        if ((not hasattr(self, 'desktop')) or (self.desktop is None)):
            print "Some dude is trying to send a message with uicore.Message before  it's ready.",
            print msgkey,
            print dict,
            print buttons,
            print suppress
            try:
                log.general.Log(("Some dude is trying to send a message with uicore.Message before  it's ready.  %s,%s,%s,%s" % (strx(msgkey),
                 strx(dict),
                 strx(buttons),
                 strx(suppress))), log.LGERR)
                flag = 0
                flag |= 48
                flag |= 8192
                blue.os.MessageBox(msg.text, msg.title, flag)
            except:
                sys.exc_clear()
            return 
        if ((buttons is not None) and (msg.type not in ('warning', 'question'))):
            raise RuntimeError('Cannot override buttons except in warning and question', msg, buttons, msg.type)
        supp = settings.user.suppress.Get(('suppress.' + msgkey), None)
        if (supp is not None):
            if (suppress is not None):
                return suppress
            else:
                return supp
        if (msg.type in ('info', 'infomodal', 'warning', 'question', 'error', 'fatal')):
            supptext = None
            if msg.suppress:
                if (buttons in [None, uiconst.OK]):
                    supptext = mls.UI_SHARED_SUPPRESS1
                else:
                    supptext = mls.UI_SHARED_SUPPRESS2
            if (buttons is None):
                buttons = uiconst.OK
            msg.icon = (msg.icon or None)
            icon = (msg.icon or None)
            if (icon is None):
                icon = {'info': uiconst.INFO,
                 'infomodal': uiconst.INFO,
                 'warning': uiconst.WARNING,
                 'question': uiconst.QUESTION,
                 'error': uiconst.ERROR,
                 'fatal': uiconst.FATAL}[msg.type]
            customicon = None
            if dict:
                customicon = dict.get('customicon', None)
            (ret, supp,) = self.MessageBox(msg.text, msg.title, buttons, icon, supptext, customicon, default=default, modal=modal)
            if (supp and (ret not in (uiconst.ID_CLOSE, uiconst.ID_CANCEL))):
                settings.user.suppress.Set(('suppress.' + msgkey), ret)
                self.SaveSettings()
            return ret
        if (msg.type in ('notify', 'hint', 'event')):
            try:
                import gameui
                (ret, supp,) = gameui.Say(msg.text)
            except:
                self.Say(msg.text)
        elif (msg.type != 'audio'):
            raise RuntimeError('Unknown message type', msg)



    def MessageBox(self, text, title = 'Wod', buttons = None, icon = None, suppText = None, customicon = None, height = None, blockconfirmonreturn = 0, default = None, modal = True):
        if not getattr(self, 'desktop', None):
            return 
        else:
            if (buttons is None):
                buttons = uiconst.ID_OK
            msgbox = self.registry.GetOrCreateWindow(decoClass=uicls.MessageBox, name='modal', parent=self.layer.abovemain)
            msgbox.blockconfirmonreturn = blockconfirmonreturn
            msgbox.Execute(text, title, buttons, icon, suppText, customicon, height, default=default)
            if modal:
                ret = msgbox.ShowModal()
            else:
                ret = msgbox.ShowDialog()
            return (ret, msgbox.suppress)



    def Say(self, msgtext, time = 100):
        if not self.triapp:
            return 
        for each in self.layer.abovemain.children[:]:
            if (each.name == 'message'):
                each.ShowMsg(msgtext)
                return 

        message = uicls.Message(parent=self.layer.abovemain, name='message')
        message.ShowMsg(msgtext)



    def _ExceptionHandler(self, exctype, exc, tb, message = ''):
        try:
            if isinstance(exc, UserError):
                self.Message(exc.msg, exc.dict)
            elif isinstance(exc, TaskletExit):
                return 
            toMsgWindow = prefs.GetValue('exceptionPopups', 0)
            if (isinstance(exc, RuntimeError) and (len(exc.args) and (exc.args[0] == 'ErrMessageNotFound'))):
                if toMsgWindow:
                    self.Message('ErrMessageNotFound', exc.args[1])
            else:
                if (getattr(exc, 'msg', None) == 'DisconnectedFromServer'):
                    toMsgWindow = 0
                extraText = '; caught by ExceptionHandler'
                if message:
                    extraText += ('\nContext info: ' + message)
                return log.LogException(extraText=extraText, toMsgWindow=toMsgWindow, exctype=exctype, exc=exc, tb=tb, severity=log.LGERR)
        except:
            exctype = exc = tb = None
            print 'Something fux0red with default exception handling!!'
            traceback.print_exc()



    def WaitForResourceLoad(self):
        fence = self.tridev.GetCurrentResourceLoadFence()
        timeWaited = 0
        while (self.tridev.GetLastResourceLoadFenceReached() < fence):
            waitMs = 100
            blue.pyos.synchro.Sleep(waitMs)
            timeWaited += waitMs
            if ((timeWaited % 5000) == 0):
                log.general.Log(('WaitForResourceLoad has waited for %d seconds! (%d vs. %d)' % ((timeWaited / 1000),
                 self.tridev.GetLastResourceLoadFenceReached(),
                 fence)), log.LGERR)





def GetClass(name):
    import uicls
    custom = getattr(uicls, name, None)
    if custom:
        return custom
    core = getattr(uicls, (name + 'Core'), None)
    if core:
        return core
    log.LogError('Unknown class request', name)
    raise AttributeError(('UI Class %s not found' % (name)))


uicorebase = UICoreBase()

def GetContainer():

    def ret():
        import uicls
        return uicls.NewContainer


    return ret()


ret = {'uicls.Get': GetClass,
 'uicls.ContainerTest': GetContainer(),
 'gameui._boot': 1,
 'uiutil._boot': 1,
 'uitest._boot': 1,
 'menu._boot': 1,
 'globalConstants._boot': 1}
exports = ret

